package kube

import (
	v1 "admin-gf/api/kube/v1"
	"context"
	"fmt"
	kv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"math"
)

func GetVersion(ctx context.Context, req *v1.GetVersionReq) (res *v1.GetVersionRes, err error) {
	res = &v1.GetVersionRes{}
	clientSet := DefaultCluster.ClientSet
	version, err := clientSet.ServerVersion()
	res.Version = version
	return
}

func GetNodeList(ctx context.Context, req *v1.GetNodeListReq) (res *v1.GetNodeListRes, err error) {
	res = &v1.GetNodeListRes{}
	nodeList, err := DefaultCluster.ClientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
	nodes := make([]Node, 0)
	for _, item := range nodeList.Items {
		node := Node{
			Name:                    item.Name,
			Labels:                  item.Labels,
			Annotations:             item.Annotations,
			CreationTimestamp:       item.CreationTimestamp.Time,
			Taints:                  item.Spec.Taints,
			Status:                  getReadyStatus(item.Status.Conditions),
			InternalIp:              getInternalIp(item.Status.Addresses),
			KernelVersion:           item.Status.NodeInfo.KernelVersion,
			KubeletVersion:          item.Status.NodeInfo.KubeletVersion,
			ContainerRuntimeVersion: item.Status.NodeInfo.ContainerRuntimeVersion,
			OsImage:                 item.Status.NodeInfo.OSImage}
		nodes = append(nodes, node)
	}
	res.NodeList = nodes
	return
}

func getInternalIp(addresses []kv1.NodeAddress) string {
	for _, address := range addresses {
		if address.Type == kv1.NodeInternalIP {
			return address.Address
		}
	}
	return "notfound"
}

func getReadyStatus(conditions []kv1.NodeCondition) string {
	for _, condition := range conditions {
		if condition.Type == kv1.NodeReady {
			return string(condition.Status)
		}
	}
	return "notfound"
}

func GetClusterInfo(ctx context.Context, req *v1.GetClusterInfoReq) (res *v1.GetClusterInfoRes, err error) {
	extraClusterInfo := ClusterInfo{}

	clientSet := DefaultCluster.ClientSet

	nodeList, err := clientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
	if err != nil {
		return
	}
	var (
		TotalMemory float64
		UsedMemory  float64
	)
	nodes := nodeList.Items
	extraClusterInfo.TotalNodeNum = len(nodes)
	for i := range nodes {
		conditions := nodes[i].Status.Conditions
		for i := range conditions {
			if conditions[i].Type == "Ready" {
				if conditions[i].Status == "True" {
					extraClusterInfo.ReadyNodeNum += 1
				}
			}
		}
		cpu := nodes[i].Status.Allocatable.Cpu().AsApproximateFloat64()
		extraClusterInfo.TotalCpu += cpu
		memory := nodes[i].Status.Allocatable.Memory().AsApproximateFloat64()
		TotalMemory += memory
	}

	podsList, err := clientSet.CoreV1().Pods("").List(ctx, metav1.ListOptions{})
	if err != nil {
		return
	}
	pods := podsList.Items
	for i := range pods {
		for j := range pods[i].Spec.Containers {
			cpu := pods[i].Spec.Containers[j].Resources.Requests.Cpu().AsApproximateFloat64()
			extraClusterInfo.UsedCpu += cpu
			memory := pods[i].Spec.Containers[j].Resources.Requests.Memory().AsApproximateFloat64()
			UsedMemory += memory
		}
	}
	extraClusterInfo.UsedCpu = CovertRate(extraClusterInfo.UsedCpu)
	extraClusterInfo.UsedMemoryRate = CovertRate((UsedMemory / TotalMemory) * 100)
	extraClusterInfo.UsedMemory = UsedMemory
	extraClusterInfo.TotalMemory = TotalMemory
	res = &v1.GetClusterInfoRes{Info: extraClusterInfo}
	return
}

func CovertRate(number float64) float64 {
	return math.Round(number*100) / 100
}

func CovertByte(size float64) string {
	// 转换byte单位
	switch {
	case size >= 1024 && size < 1024*1024:
		return CovertByte(size/1024) + "KB"
	case size >= 1024*1024 && size < 1024*1024*1024:
		return CovertByte(size/(1024*1024)) + "MB"
	case size >= 1024*1024*1024:
		return CovertByte(size/(1024*1024*1024)) + "GB"
	default:
		return fmt.Sprint(size)
	}
}
